//
//  JSONMappedObject.m
//  oos4ios
//
//  Created by Pablo Gonzalez on 7/22/11.
//  Copyright 2011 11870.com. All rights reserved.
//

#import "JSONMappedObject.h"
#import "../../../External/JSON/JSON.h"
#import "../../../Utils/NSDictionary+Path.h"
#import "../Exceptions/MethodNotImplementedException.h"

@implementation SelectorDescriptor

@synthesize name;
@synthesize type;

- (void)dealloc
{
    [name release];
    [super dealloc];
}

static NSMutableDictionary *descriptorCache;


+ (SelectorDescriptor *)descriptorForString:(NSString *)fullname
{
    SelectorDescriptor *descriptor = nil;
    if (!descriptorCache) {
        descriptorCache = [[NSMutableDictionary dictionary] retain];
    } else {
        descriptor = [descriptorCache objectForKey:fullname];
    }
    
    if (!descriptor) {
        SelectorType type;
        NSString *name = nil;
        if ([fullname hasPrefix:@"set"]) {
            type = setter;
            name = [fullname stringByReplacingOccurrencesOfString:@"set" 
                                                       withString:@""];
        } else if ([fullname hasPrefix:@"add"]) {
            type = adder;
            name = [fullname stringByReplacingOccurrencesOfString:@"add" 
                                                       withString:@""];
        } else if ([fullname hasPrefix:@"remove"]) {
            type = remover;
            name = [fullname stringByReplacingOccurrencesOfString:@"remove" 
                                                       withString:@""];
        } else {
            type = getter;
            name = [fullname copy];
        }
        // lowercase first letter
        NSString *firstLetter = [[name substringToIndex:1] lowercaseString];
        [name stringByReplacingCharactersInRange:NSMakeRange(0, 1) 
                                      withString:firstLetter];
        // create descriptor
        descriptor = [[SelectorDescriptor new] autorelease];
        descriptor.type = type;
        descriptor.name = name;
        [descriptorCache setObject:descriptor forKey:fullname];
    }
    return descriptor;
}

+ (SelectorDescriptor *)descriptorForSelector:(SEL)aSelector
{
    return [self descriptorForString:NSStringFromSelector(aSelector)];
}

@end

@implementation JSONMappedObject

- (NSDictionary *)pathDictionary
{
    return [NSDictionary dictionary];
}

- (NSArray *)indexes
{
    [MethodNotImplementedException raiseForSelector:_cmd inObject:self];
    return nil;
}

- (NSArray *)relationships
{
    [MethodNotImplementedException raiseForSelector:_cmd inObject:self];
    return nil;
}

- (id)init
{
    self = [super init];
    if (self) {
        pathDictionary = [[self pathDictionary] retain];
        keys = [[pathDictionary allKeys] retain];
    }
    return self;
}

- (void)dealloc
{
    [jsonString release];
    [jsonObject release];
    [pathDictionary release];
    [keys release];
    [super dealloc];
}

- (id)performSelector:(SEL)aSelector
{
    return [self performSelector:aSelector withObject:nil];
}

- (id)performSelector:(SEL)aSelector withObject:(id)object
{
    if (!jsonObject) {
        // lazily parse the json object
        jsonObject = [jsonString JSONValue];
    }
    NSString *path = [pathDictionary objectForKey:NSStringFromSelector(aSelector)];
    SelectorDescriptor *descriptor = [SelectorDescriptor descriptorForSelector: aSelector];
    
    switch (descriptor.type) {
        case getter:
            return [jsonObject objectForPath:path];
            break;
        case setter:
            
            break;
        default:
            break;
    }
    return nil;
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    SelectorDescriptor *descriptor = [SelectorDescriptor descriptorForSelector: aSelector];
    if ([keys indexOfObject:descriptor.name] != NSNotFound) {
        return YES;
    }
    return NO;
}

- (id)initWithJson:(NSString *)json
{
    self = [self init];
    if (self) {
        jsonString = [json retain];
    }
    return self;
}

+ (id)objectWithJson:(NSString *)json
{
    return [[[JSONMappedObject alloc] initWithJson:json] autorelease];
}

@end
